/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       rendertexture.cpp
 * Author:     twoja stara
 * Created on: 2009-09-15
 *
 **********************************************************************************************************************/

#include "rendertexture.h"

namespace mGameEngine
{
namespace Graphics
{

// maximum render texture size
static const uint RTSIZE = 2048;

RenderTexture::RenderTexture() :
    RenderTarget(),
    Texture(),
    _fboId(0), _rboId(0)
{
    _type = TEX_2D;
    _size = Vector2(1, 1);
    _init();
}

RenderTexture::RenderTexture(const Vector2 &size,
                                TextureWrapping wrap,
                                TextureFiltering filter) :
    RenderTarget(),
    Texture(NULL, wrap, filter),
    _fboId(0), _rboId(0)
{
    _type = TEX_2D;
    _size = size;
    _init();
}

RenderTexture::~RenderTexture()
{
    glDeleteRenderbuffersEXT(1, &_rboId);
    glDeleteFramebuffersEXT(1, &_fboId);
}

void RenderTexture::_init()
{
    // create framebuffer object
    glGenFramebuffersEXT(1, &_fboId);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fboId);

    // create and attach texture image
    glBindTexture(GL_TEXTURE_2D, _id);
    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
    glTexImage2D(GL_TEXTURE_2D,
                0, GL_RGBA16,
                int(_size.x), int(_size.y), 0,
                GL_RGBA, GL_UNSIGNED_SHORT,
                NULL);
    glBindTexture(GL_TEXTURE_2D, 0);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
                            GL_COLOR_ATTACHMENT0_EXT,
                            GL_TEXTURE_2D, _id, 0);

    // create and attach renderbuffer for depth component
    glGenRenderbuffersEXT(1, &_rboId);
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _rboId);
    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
                        GL_DEPTH_COMPONENT,
                        int(_size.x), int(_size.y));
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
                            GL_DEPTH_ATTACHMENT_EXT,
                            GL_RENDERBUFFER_EXT, _rboId);

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

void RenderTexture::setSize(const Vector2 &size)
{
    if(size == _size || size.x < 0.0f || size.y < 0.0f)
    {
        return;
    }

    _size = size;
    
    // reinitialize texture with new size
    glDeleteRenderbuffersEXT(1, &_rboId);
    glDeleteFramebuffersEXT(1, &_fboId);
    _init();
}

void RenderTexture::beginRendering()
{
    // select fbo for rendering
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fboId);
    glViewport(0, 0, int(_size.x), int(_size.y));

    // TODO render to cube texture - consider _face
}

void RenderTexture::endRendering()
{
    // select standard rendering window
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

    // generate mipmaps
    glBindTexture(GL_TEXTURE_2D, _id);
    glGenerateMipmapEXT(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);
}

}
}

